#pragma once

#include "Tool.hpp"
#include "HttpRequest.hpp"
#include "HttpResponse.hpp"
#include "HttpContext.hpp"
#include "TcpServer.hpp"

class HttpServer
{
    typedef function<bool(HttpRequest &, HttpResponse *)> DynamicFunction;

private:
    // 动态功能路由表：
    vector<pair<regex, DynamicFunction>> _get_handles;
    vector<pair<regex, DynamicFunction>> _post_handles;
    vector<pair<regex, DynamicFunction>> _put_handles;
    vector<pair<regex, DynamicFunction>> _delete_handles;
    // 静态资源根目录(web根目录)
    string _basedir;
    // TCP高性能服务器
    TcpServer _tcp_server;

    bool PrintRequest(HttpRequest &req)
    {
        stringstream ss;
        // 请求行
        ss << "请求行：\r\n"
           << req._method << " " << req._uri << " " << req._version << "\r\n";

        ss << "查询字符串：\r\n";
        // 查询字符串
        for (auto &e : req._params)
        {
            ss << e.first << "=" << e.second << "\r\n";
        }

        // 空行
        ss << "\r\n";

        ss << "请求报头：\r\n";
        // 请求头部
        for (auto &e : req._headers)
        {
            ss << e.first << ": " << e.second << "\r\n";
        }

        // 空行
        ss << "\r\n";

        ss << "请求正文：\r\n";
        // 请求正文
        ss << req._body;

        string data = ss.str();
        cout << data;
        return true;
    }

private:
    // 判断是否为静态请求->此为浅显判断，如果动态功能路由失败，还会再次尝试一次静态路由
    bool IsStaticResources(HttpRequest &requ)
    {
        // 使用正则表达式解析url，根据请求的文件的后缀名判断是否为静态资源请求
        // 编写正则表达式，定义成static，因为正责表达式编译消耗高
        static std::regex r(".*\\.(html|htm|css|js|png|jpg|gif|svg|mp3|mp4|avi|pdf|docx|xlsx)$");

        // 如果匹配成功就说明是静态资源
        return std::regex_match(requ._uri, r);
    }
    // 错误页面的生成和填充
    void ErrorHandle(HttpResponse *resp)
    {
        // 根据响应状态码，决定返回的错误页面对应的文件
        int code = resp->_status_code;

        // 拼接文件路径
        // string file_name = "Error-" + to_string(code);

        // 先统一返回404页面
        string file_name = _basedir + "/NotFound.html";

        // 打开文件并读取文件内容
        if (Tool::ReadFile(file_name, &(resp->_body)) == false)
        {
            LOG(LogLevel::DEADLY) << "stutas_code: " << code << "对应页面不存在";
            abort();
        }
        // 填充响应头部
        // 指定正文类型
        resp->InsertHead("Content-Type", Tool::ExtMime(file_name));
        // 指定正文长度
        resp->InsertHead("Content-Length", to_string(resp->_body.size()));
    }
    // 静态资源路由
    bool StaticRouter(HttpRequest &requ, HttpResponse *resp)
    {
        // 拼接资源路径
        string file_path = _basedir + requ._uri;

        // 如果路径存在且为目录
        if (Tool::IsDirectory(file_path))
        {
            // 让路径指向该目录的首页
            file_path += "index.html";
        }

        // 再判断，如果路径存在且为文件
        if (Tool::IsRegularFile(file_path))
        {
            // 打开文件并读取文件内容
            if (Tool::ReadFile(file_path, &(resp->_body)) == false)
            {
                // 如果读取失败，构建404页面
                resp->_status_code = 404;
                ErrorHandle(resp);
                return false;
            }
            // 填充响应头部
            resp->InsertHead("Content-Type", Tool::ExtMime(file_path));
            resp->InsertHead("Content-Length", to_string(resp->_body.size()));
        }
        else // 如果不是文件，就判定为资源不存在
        {
            // 如果读取失败，构建404页面
            resp->_status_code = 404;
            ErrorHandle(resp);
            return false;
        }
        return true;
    }
    // 动态功能路由
    bool DynamicRouter(HttpRequest &requ, HttpResponse *resp, vector<pair<regex, DynamicFunction>> &handles)
    {
        // 遍历动态功能路由表
        for (auto &e : handles)
        {
            regex &reg = e.first;
            DynamicFunction &func = e.second;
            // 使用正则比较，判断是否存在对应的动态处理函数
            bool ret = regex_match(requ._uri, reg);
            if (ret == false)
            {
                // 不存在就下一个
                continue;
            }
            // 匹配成功了就执行
            return func(requ, resp);
        }
        // 如果都匹配不上
        return false;
    }
    // 功能路由
    void Router(HttpRequest &requ, HttpResponse *resp)
    {
        // 判断是否为静态请求
        if (IsStaticResources(requ))
        {
            LOG(LogLevel::DEBUG) << "---------进入静态资源路由---------------";
            // 如果是静态请求
            StaticRouter(requ, resp);
        }
        else
        {
            LOG(LogLevel::DEBUG) << "---------进入动态资源路由---------------";
            bool ret = true;
            // 如果是动态请求
            // 根据请求方法决定使用哪个功能路由表
            if (requ._method == "GET" || requ._method == "HEAD")
            {
                ret = DynamicRouter(requ, resp, _get_handles);
            }
            else if (requ._method == "POST")
            {
                ret = DynamicRouter(requ, resp, _post_handles);
            }
            else if (requ._method == "DELETE")
            {
                ret = DynamicRouter(requ, resp, _delete_handles);
            }
            else if (requ._method == "PUT")
            {
                ret = DynamicRouter(requ, resp, _put_handles);
            }
            else
            {
                LOG(LogLevel::WARNING) << "用户使用了，服务器不支持的请求方法";
                // 用户使用了，服务器不支持的请求方法,设置错误码为405
                resp->_status_code = 405;
                ErrorHandle(resp);
                return;
            }
            // 如果动态路由查找失败，再尝试一下静态路由处理
            if (ret == false)
            {
                StaticRouter(requ, resp);
            }
        }
    }
    // 解析处理Buffer接收缓冲区数据(是设置给_tcp_server的回调函数)
    void OnOperations(shared_ptr<Connection> connection, Buffer *buf)
    {
        while (true)
        {
            // 从连接获取之前保存的上下文对象,使用引用接收，防止函数结束栈区清空导致已经处理的上下文被销毁
            HttpContext &content = (connection->GetContext())->Data<HttpContext>();

            // 定义响应对象
            HttpResponse resp;
            // 从连接对应的接收缓冲区读取数据，用于后续填充HttpRequest
            if (content.RecvRequest(buf) == 0)
            {
                LOG(LogLevel::DEBUG) << "-----报文不完整-----";
                //==0就是请求报文不完整
                // 结束函数
                return;
            }
            // 填充状态码
            resp._status_code = content.ResponseStatuCode();

            // 标识是否为短连接
            bool is_shortConnections = true;

            // 根据HttpRequest构建HttpResponse
            // 判断当前上下文状态
            if (content.RecvStatu() == HttpRecvStatus::RECV_HTTP_OVER)
            {
                // 如果全部处理完成，就获取对象
                HttpRequest &requ = content.Request();

                // debug
                LOG(LogLevel::DEBUG) << "客户端请求报文: ";
                // PrintRequest(requ);

                // 填充协议版本
                resp.SetVersion(requ._version);

                // 判断是否为短连接
                if (requ.IsShortConnections())
                {
                    is_shortConnections = true;
                    // 如果是短连接
                    resp.InsertHead("Connection", "close");
                }
                else
                {
                    is_shortConnections = false;
                    resp.InsertHead("Connection", "keep-alive");
                }

                // 开始功能路由
                Router(requ, &resp);
            }
            else if (content.RecvStatu() == HttpRecvStatus::RECV_HTTP_ERROR)
            {
                LOG(LogLevel::DEBUG) << "-----请求报文异常-----";
                // 清空连接对应的接收缓冲区
                buf->Clear();
                // 如果接收/解析请求报文错误，则构建错误页面
                ErrorHandle(&resp);
            }

            // 序列化HttpResponse
            string data = resp.Serialization();

            LOG(LogLevel::DEBUG) << "响应报文: " << data;

            // 发送序列化之后的HttpResponse
            connection->Send(data);

            // 根据长短连接，判断是否继续循环执行处理//
            // 如果是短连接
            if (is_shortConnections == true)
            {
                // 则处理一份请求报文
                // 就清空连接中保存的上下文
                content.Reset();
                // 然后关闭连接
                connection->Shutdown();
                // 并退出循环
                break;
            }
            else // 如果是长连接
            {
                // 就清空连接中保存的上下文,准备处理下一份请求报文
                content.Reset();
            }
        }
    }
    // 处理接收缓冲区容量超限方式 1 --一边接收一边处理（支持流式处理的协议可以采用）
    void HandleBufferExceededLimit(shared_ptr<Connection> connection, Buffer *buf, bool *is_close_connection)
    {
        LOG(LogLevel::DEBUG) << "开始HandleBufferExceededLimit";
        // 不关闭该连接
        *is_close_connection = false;

        // 直接调用业务处理函数
        OnOperations(connection, buf);
    }

    // 处理接收缓冲区容量超限方式 2 --回应错误页面后，关闭该连接
    /*void HandleBufferExceededLimit(shared_ptr<Connection> connection, Buffer *buf, bool *is_close_connection)
    {
        LOG(LogLevel::DEBUG)<<"开始HandleBufferExceededLimit";
        // 需要关闭该连接
        *is_close_connection = true;

        // 从连接获取之前保存的上下文对象,使用引用接收
        HttpContext &content = (connection->GetContext())->Data<HttpContext>();

        // 定义响应对象
        HttpResponse resp;

        // 填充状态码
        resp._status_code = 400;

        // 填充协议版本
        HttpRequest &requ = content.Request();
        // 不为空，即成功解析到了协议版本，才能填充
        if (requ._version.empty() == false)
        {
            resp._version = requ._version;
        }

        LOG(LogLevel::DEBUG) << "-----请求报文异常-----";

        //清空连接对应的接收缓冲区
        buf->Clear();
        // 构建错误页面
        ErrorHandle(&resp);

        // 序列化HttpResponse,此处会调用右值拷贝
        string data = resp.Serialization();

        LOG(LogLevel::DEBUG) << "响应报文: " << data;

        // 发送序列化之后的HttpResponse
        connection->Send(data);

        // 就清空连接中保存的上下文
        content.Reset();
        // 然后关闭连接
        connection->Shutdown();
    }*/

public:
    HttpServer(uint16_t port, string basedir, int timerout = 30)
        : _basedir(basedir),
          _tcp_server(port)
    {
        if (Tool::IsDirectory(basedir) == false)
        {
            LOG(LogLevel::DEADLY) << "静态资源根目录" << basedir << "不存在(或者不是目录)";
            abort();
        }
        if (_basedir.back() == '/')
        {
            _basedir.pop_back();
        }
        // 默认开启非活跃连接超时销毁
        _tcp_server.EnableInactiveRelease(timerout);

        // 把OnOperations作为业务处理回调注册给TcpServer
        // 把HandleBufferExceededLimit作为处理接收缓冲区容量超限处理回调注册给TcpServer
        _tcp_server.HandoffAgreement(
            HttpContext(),
            std::bind(&HttpServer::OnOperations, this, std::placeholders::_1, std::placeholders::_2),
            std::bind(&HttpServer::HandleBufferExceededLimit, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }
    // 设置静态资源更目录
    void SetBaseDir(const string &basedir)
    {
        if (Tool::IsDirectory(basedir) == false)
        {
            LOG(LogLevel::DEADLY) << "静态资源根目录" << basedir << "不存在(或者不是目录)";
            abort();
        }
        _basedir = basedir;
    }
    // 设置_tcp_server的从属Reactor线程个数
    void SetReactorThreadCount(uint32_t count)
    {
        _tcp_server.SetThreadConnection(count);
    }

    // 根据组件使用者指定的秒（参数sec）启动非活跃连接超时销毁
    void EnableInactiveRelease(int sec)
    {
        _tcp_server.EnableInactiveRelease(sec);
    }
    // 关闭非活跃连接超时销毁
    void CancelInactiveRelease()
    {
        _tcp_server.CancelInactiveRelease();
    }
    // 向GET功能路由表中插入
    void InsertGetHandles(const string &regular_expression, const DynamicFunction &func)
    {
        // 编译并插入正则表达式
        _get_handles.emplace_back(regex(regular_expression), func);
    }
    // 向POST功能路由表中插入
    void InsertPostHandles(const string &regular_expression, const DynamicFunction &func)
    {
        // 编译正则表达式
        _post_handles.emplace_back(regex(regular_expression), func);
    }
    // 向PUT功能路由表中插入
    void InsertPutHandles(const string &regular_expression, const DynamicFunction &func)
    {
        // 编译正则表达式
        _put_handles.emplace_back(regex(regular_expression), func);
    }
    // 向DELETE功能路由表中插入
    void InsertDeleteHandles(const string &regular_expression, const DynamicFunction &func)
    {
        // 编译正则表达式
        _delete_handles.emplace_back(regex(regular_expression), func);
    }

    // 启动服务器
    void Start()
    {
        _tcp_server.Start();
    }
};